{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": [],
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/Maplemx/Agently/blob/main/playground/survey_agent_asks_questions_according_form.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "# Survey Agent Asks Questions According Form"
      ],
      "metadata": {
        "id": "dAzfqHDCAXZe"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Demo Description\n",
        "\n",
        "**Author:** Agently Team\n",
        "\n",
        "**Prompt Language:** English\n",
        "\n",
        "**Agent Components:** Role\n",
        "\n",
        "**Description:**\n",
        "\n",
        "This case shows how to use Agently framework to create a survey agent asking questions according the survey form, communicate with customer, collecting feedbacks using natural language. During the survey, customer may tell a story or jump out of the question to say something else and the agent can try its best to handle this complex situation. This case shows how agent handle complex task and maybe you can modified the demo code to make it work better?\n",
        "\n",
        "本案例演示了如何使用Agently框架创建一个问卷调查agent，通过自然语言问答的方式和客户交流，回收问卷信息。在交流过程中，客户有可能会跳出当前的问题讲一些别的事情，这对于agent而言会是一个挑战。可以看看agent能否处理这些复杂的场景。这个案例展现了agent处理复杂任务的一种思路，你可以在这个基础上进一步优化，或许你的思路会让agent做得更好？"
      ],
      "metadata": {
        "id": "kyLFmv_l-aIx"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Step 1: Install Packages"
      ],
      "metadata": {
        "id": "nRsfMu4lAJZF"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!pip install Agently"
      ],
      "metadata": {
        "id": "nsst7pOAANlr"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Step 2: Demo Code"
      ],
      "metadata": {
        "id": "_-1gryYwASPM"
      }
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "lLaK-w-E-ZKU",
        "outputId": "c348f95e-ce7b-47a1-b421-f047a13234a0"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[Survey Agent]:  Hello, and welcome to the Green City Kitchen customer survey. We value your feedback and aim to provide the best dining experience for our customers. Your input will help us improve our services. Thank you for taking the time to participate in this survey.\n",
            "[Survey Agent]:  Thank you for participating in our survey! May I please have your name?\n",
            "[Customer]:  Sam, Sam Green\n",
            "[Survey Agent]:  Thank you, Sam Green, for providing your name! We appreciate your participation.\n",
            "[Survey Agent]:  May I have your phone number for contact purposes? (Optional)\n",
            "[Customer]:  Emmm, I'd rather not sharing my phone number.\n",
            "[Survey Agent]:  I completely understand, Sam Green. Your phone number is optional, so feel free to skip providing it. Is there anything else you would like to share or any other feedback you have for us?\n",
            "[Survey Agent]:  Could you please share the date and time of your recent dining experience with us? This will help us understand better the timing and flow of our services.\n",
            "[Customer]:  last Saturday noon I think\n",
            "[Survey Agent]:  Thank you for sharing the date and time of your recent dining experience with us. We appreciate the valuable feedback.\n",
            "[Survey Agent]:  On a scale of 1 to 10, how would you rate your overall satisfaction with your recent dining experience at Green City Kitchen?\n",
            "[Customer]:  7 or 8\n",
            "[Survey Agent]:  Thank you for sharing your rating. Your feedback is important to us and will help us improve our services. Is there anything specific that contributed to your rating that you would like to share?\n",
            "[Survey Agent]:  What is your favorite food that you had during your recent dining experience with us?\n",
            "[Customer]:  I think your steak was great, it was juicy and ice tea was so perfect. Also I like the view outside the window. And may I ask a question? Can I make birthday party appointment for my son next month at your place?\n",
            "[Survey Agent]:  It's great to hear that you enjoyed the steak and iced tea! I'm glad to hear positive feedback. Regarding the birthday party appointment, I'll be happy to assist you with that. Could you provide me with more details about the date and the number of guests so that I can check availability and discuss the arrangements with our team?\n",
            "[Customer]:  I'd like to say in the evening on Jan 12th and there'll be 5 of us.\n",
            "[Survey Agent]:  It's great to hear that you enjoyed the steak and iced tea! I'm glad to hear the positive feedback. Regarding the birthday party appointment, I'll be happy to assist you with that. Could you provide me with more details about the date and the number of guests so that I can check availability and discuss the arrangements with our team?\n",
            "[Customer]:  In the evening on Jan 12th and there'll be 5 of us.\n",
            "[Survey Agent]:  Thank you for sharing your favorite food and the details about your upcoming event. I'll make sure to check the availability and get back to you with the arrangements for the birthday party. Is there anything else you would like to add or inquire about?\n",
            "[Survey Agent]:  We understand your preference for not sharing your phone number. If there's any other way you'd like us to contact you regarding the birthday party appointment, please let us know. We strive to make the event special for your son and want to ensure we have all the necessary details.\n",
            "[Customer]:  You can email me. sam_green@gmail.com\n",
            "[Survey Agent]:  Thank you for sharing your email, Sam Green. We'll use sam_green@gmail.com to contact you regarding the birthday party appointment. We strive to make the event special for your son and want to ensure we have all the necessary details. Is there anything else you would like to add or inquire about?\n",
            "[Survey Agent]:  Thank you for the detailed information about your recent dining experience and the upcoming event. Could you share any specific details or requests for the birthday party on Jan 12th in the evening? This will help us ensure we make the event special for your son.\n",
            "[Customer]:   I'd like your seats beside the window with beautiful view of the sea. That's all.\n",
            "[Survey Agent]:  Thank you for sharing your preference. We'll make sure to arrange the seats beside the window for the beautiful view of the sea for the birthday party on Jan 12th in the evening. Is there anything else you would like to add or inquire about?\n",
            "[Survey Agent]:  Thank you for your participation, Sam Green! We appreciate your feedback and look forward to serving you again. Have a great day!\n",
            "[Survey Form]:\n",
            " {'prefer_language': {'value': None}, 'name': {'value': 'Sam Green', 'customer_explation': ['Sam, Sam Green'], 'data_type': 'String', 'optional': False}, 'phone': {'value': None, 'customer_explation': [\"I'd rather not sharing my phone number.\", 'You can email me. sam_green@gmail.com'], 'data_type': 'Number', 'optional': True}, 'dining time': {'value': 'evening on Jan 12th', 'customer_explation': ['I think', \"I'd like your seats beside the window with a beautiful view of the sea. That's all.\"], 'data_type': 'Date String', 'optional': True}, 'satisfaction': {'value': 7, 'customer_explation': [], 'data_type': 'Number: 1-10, 10 is the best, 1 is the worst', 'optional': True}, 'favourite food': {'value': 'The steak and iced tea', 'customer_explation': [\"During the evening on Jan 12th and there'll be 5 of us.\"], 'data_type': 'String', 'optional': True}, 'commendation': {'value': None, 'customer_explation': [], 'data_type': 'String', 'optional': True}, 'criticism': {'value': None, 'customer explation': [], 'data_type': 'String', 'optional': True}, 'comments_and_add_up': {'value': None, 'customer_explation': [], 'data_type': 'Boolean', 'optional': True, 'comments': \"It's for add up information during the survey. Make sure update the full value each time you need to update\"}}\n"
          ]
        }
      ],
      "source": [
        "from datetime import datetime\n",
        "import Agently\n",
        "\n",
        "agent_factory = Agently.AgentFactory()\n",
        "\n",
        "agent_factory\\\n",
        "    .set_settings(\"model.OpenAI.auth\", { \"api_key\": \"\" })\\\n",
        "    .set_settings(\"model.OpenAI.options\", { \"model\": \"gpt-3.5-turbo-1106\" })\n",
        "\n",
        "survey = {\n",
        "    \"name\": {\n",
        "        \"value\":  None,\n",
        "        \"customer_explation\": [],\n",
        "        \"data_type\": \"String\",\n",
        "        \"optional\": False,\n",
        "    },\n",
        "    \"phone\": {\n",
        "        \"value\": None,\n",
        "        \"customer_explation\": [],\n",
        "        \"data_type\": \"Number\",\n",
        "        \"optional\": True,\n",
        "    },\n",
        "    \"dining time\": {\n",
        "        \"value\":  None,\n",
        "        \"customer_explation\": [],\n",
        "        \"data_type\": \"Date String\",\n",
        "        \"optional\": True,\n",
        "    },\n",
        "    \"satisfaction\": {\n",
        "        \"value\": None,\n",
        "        \"customer_explation\": [],\n",
        "        \"data_type\": \"Number: 1-10, 10 is the best, 1 is the worst\",\n",
        "        \"optional\": False,\n",
        "    },\n",
        "    \"favourite food\": {\n",
        "        \"value\": None,\n",
        "        \"customer_explation\": [],\n",
        "        \"data_type\": \"String\",\n",
        "        \"optional\": True,\n",
        "    },\n",
        "    \"commendation\": {\n",
        "        \"value\": None,\n",
        "        \"customer_explation\": [],\n",
        "        \"data_type\": \"String\",\n",
        "        \"optional\": True,\n",
        "    },\n",
        "    \"criticism\": {\n",
        "        \"value\": None,\n",
        "        \"customer explation\": [],\n",
        "        \"data_type\": \"String\",\n",
        "        \"optional\": True,\n",
        "    },\n",
        "    \"comments_and_add_up\": {\n",
        "        \"value\": None,\n",
        "        \"customer_explation\": [],\n",
        "        \"data_type\": \"Boolean\",\n",
        "        \"optional\": True,\n",
        "        \"comments\": \"It's for add up information during the survey. Make sure update the full value each time you need to update\",\n",
        "    },\n",
        "}\n",
        "\n",
        "def start_survey(survey: dict):\n",
        "    agent = agent_factory.create_agent()\n",
        "    # Prepare Basic Information for Agent\n",
        "    agent\\\n",
        "        .set_role(\"Role\", \"Green City Kitchen Survey Expert\")\\\n",
        "        .set_role(\"NAME\", \"Jack Grayson\")\\\n",
        "        .general(\n",
        "            \"Introduce of Green City Kitchen\",\n",
        "            \"1457, Sunshine Street, Fake City.\" + \\\n",
        "            \"Beautiful view of the seaside.\" + \\\n",
        "            \"Open from 10:30am to 10:30pm \" + \\\n",
        "            \"providing brunch, lunch and dinner.\" + \\\n",
        "            \"Ordering Number: 35671881\" + \\\n",
        "            \"Party appointments are accepted.\"\n",
        "        )\\\n",
        "        .general(\n",
        "            \"Current Date\",\n",
        "            datetime.now().date()\n",
        "        )\n",
        "    # Start the Survey\n",
        "    can_stop = False\n",
        "    chat_history = []\n",
        "    opening = agent\\\n",
        "        .input({\n",
        "            \"survey\": survey,\n",
        "        })\\\n",
        "        .output({\n",
        "            \"opening\": (\n",
        "                \"String\",\n",
        "                \"Your warm opening about this survey \" + \\\n",
        "                \"and introduce the background of this survey \" + \\\n",
        "                \"like who you are and which dining customer had is being reviewed\"\n",
        "            ),\n",
        "        })\\\n",
        "        .start()\n",
        "    print(\"[Survey Agent]: \", opening[\"opening\"])\n",
        "    # Update logic to suit some models require chat history strictly follow the\n",
        "    # order: user-assistant-user-assistant\n",
        "    chat_history.extend([\n",
        "        { \"role\": \"user\", \"content\": \"hi\" },\n",
        "        { \"role\": \"assistant\", \"content\": opening[\"opening\"] }\n",
        "    ])\n",
        "    # This logic down below works perfect for OpenAI GPT\n",
        "    '''\n",
        "    chat_history.append({ \"role\": \"assistant\", \"content\": opening[\"opening\"] })\n",
        "    '''\n",
        "    while not can_stop:\n",
        "        # Planning: Check Survey Form and Ask Question\n",
        "        question_plan = agent\\\n",
        "            .chat_history(chat_history)\\\n",
        "            .instruct(\n",
        "                \"Action Rules\",\n",
        "                [\n",
        "                    \"1. Check {survey} form and make sure all filled items have complete and correct information.\",\n",
        "                    \"2. If there're incomplete or incorrect information, choose one of the items and asking customer again.\",\n",
        "                    \"3. If there're still blank items, choose one of the blank items to ask.\",\n",
        "                    \"4. Check chat history, make sure ask even optional items at least once\",\n",
        "                    \"5. Do remember to check chat history and do not repeat questions that are already asked and responsed correctly.\",\n",
        "                ]\n",
        "            )\\\n",
        "            .input({\n",
        "                \"survey\": survey,\n",
        "            })\\\n",
        "            .output({\n",
        "                \"incorrect_items\": (\"Array | Null\", \"list items names with incorrect information.\"),\n",
        "                \"target_item\": (\"String\", \"choose one target item for this question round. If there're incorrect items, ask them first.\"),\n",
        "                \"question\": (\"String\", \"your question about {target_item} to customer. Check chat history, don't repeat yourself.\"),\n",
        "            })\\\n",
        "            .start()\n",
        "        # Asking: Survey Agent Interact with Customer\n",
        "        print(\"[Survey Agent]: \", question_plan[\"question\"])\n",
        "        need_to_dig_deep = True\n",
        "        while need_to_dig_deep:\n",
        "            customer_response = input(f\"[Customer]:  \")\n",
        "            # Filling the Form: Survey Agent Analyses the Response, Fills the Form and Replies.\n",
        "            analysis = agent\\\n",
        "                .chat_history(chat_history)\\\n",
        "                .input({\n",
        "                    \"question_target_item\": question_plan[\"target_item\"],\n",
        "                    \"question\": question_plan[\"question\"],\n",
        "                    \"customer_response\": customer_response,\n",
        "                })\\\n",
        "                .info({ \"survey\": survey })\\\n",
        "                .instruct(\"Using the language customer prefer especially when customer asked clearly!!!\")\\\n",
        "                .output({\n",
        "                    \"fillings\": [{\n",
        "                        \"target_item\": (\"String\", \"according {customer_response}, which item from {survey} is response about?\"),\n",
        "                        \"value\": (\"As required\", \"value you will fill into the form about {target_item} according {survey} required\"),\n",
        "                        \"customer_explation\": (\"String | Null\", \"Extra explation from the customer\"),\n",
        "                    }],\n",
        "                    \"need_to_dig_deep\": (\"Boolean\", \"if {customer_response} is not so exactly and according chat history you think you can get more information, return true\"),\n",
        "                    \"reply\": \"Your reply to customer, to finish this item's question-answer or question to dig deep\",\n",
        "                })\\\n",
        "                .start()\n",
        "            need_to_dig_deep = analysis[\"need_to_dig_deep\"] if \"need_to_dig_deep\" in analysis else False\n",
        "            if \"fillings\" in analysis:\n",
        "                for filling in analysis[\"fillings\"]:\n",
        "                    if filling[\"target_item\"] not in survey:\n",
        "                        survey.update(filling[\"target_item\"], {})\n",
        "                    survey[filling[\"target_item\"]][\"value\"] = filling[\"value\"]\n",
        "                    if \"customer_explation\" in filling\\\n",
        "                        and filling[\"customer_explation\"] not in (None, \"\"):\n",
        "                        survey[filling[\"target_item\"]][\"customer_explation\"]\\\n",
        "                            .append(str(filling[\"customer_explation\"]))\n",
        "            print(\"[Survey Agent]: \", analysis[\"reply\"])\n",
        "            # Update logic to suit some models require chat history strictly follow the\n",
        "            # order: user-assistant-user-assistant\n",
        "            chat_history[-1][\"content\"] += \"\\n\" + question_plan[\"question\"]\n",
        "            chat_history.extend([\n",
        "                { \"role\": \"user\", \"content\": customer_response },\n",
        "                { \"role\": \"assistant\", \"content\": analysis[\"reply\"] }\n",
        "            ])\n",
        "            # This logic down below works perfect for OpenAI GPT\n",
        "            '''\n",
        "            chat_history.extend([\n",
        "                { \"role\": \"assistant\", \"content\": question_plan[\"question\"] },\n",
        "                { \"role\": \"user\", \"content\": customer_response },\n",
        "                { \"role\": \"assistant\", \"content\": analysis[\"reply\"] }\n",
        "            ])\n",
        "            '''\n",
        "        # Can Stop Check\n",
        "        can_stop_judgement = agent\\\n",
        "            .info({\n",
        "                \"survey\": survey\n",
        "            })\\\n",
        "            .output({\n",
        "                \"can_stop_judgement\": (\n",
        "                    \"Boolean\",\n",
        "                    \"if all survey required items are filled \" + \\\n",
        "                    \"and optional items are tried to ask in chat history, \" + \\\n",
        "                    \"you can stop.\"\n",
        "                ),\n",
        "                \"stop_reply\": (\"String\", \"if {hang_up_judgement} is true, generate your thanks and goodbye reply\"),\n",
        "            })\\\n",
        "            .start()\n",
        "        if can_stop_judgement[\"can_stop_judgement\"]:\n",
        "            can_stop = True\n",
        "            print(\"[Survey Agent]: \", can_stop_judgement[\"stop_reply\"])\n",
        "            chat_history[-1][\"content\"] += \"\\n\" + can_stop_judgement[\"stop_reply\"]\n",
        "            #chat_history.append({ \"role\": \"assistant\", \"content\": can_stop_judgement[\"stop_reply\"]})\n",
        "            print(\"[Survey Form]:\\n\", survey)\n",
        "\n",
        "start_survey(survey)"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "---\n",
        "\n",
        "[**_<font color = \"red\">Agent</font><font color = \"blue\">ly</font>_** Framework - Speed up your AI Agent Native application development](https://github.com/Maplemx/Agently)"
      ],
      "metadata": {
        "id": "IT3pSaO2NgkG"
      }
    }
  ]
}